package cn.com.anysdk.core.util;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * 日期时间工具类
 */
public class DateUtils {
    private DateUtils() {
        throw new IllegalStateException("Utility class");
    }

    // 常用日期时间格式
    public static final String DATE_FORMAT = "yyyy-MM-dd";
    public static final String TIME_FORMAT = "HH:mm:ss";
    public static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DATETIME_MS_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";

    // 常用日期时间格式化器
    public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT);
    public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(TIME_FORMAT);
    public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DATETIME_FORMAT);
    public static final DateTimeFormatter DATETIME_MS_FORMATTER = DateTimeFormatter.ofPattern(DATETIME_MS_FORMAT);

    /**
     * 获取当前日期
     *
     * @return 当前日期
     */
    public static LocalDate now() {
        return LocalDate.now();
    }

    /**
     * 获取当前时间
     *
     * @return 当前时间
     */
    public static LocalTime nowTime() {
        return LocalTime.now();
    }

    /**
     * 获取当前日期时间
     *
     * @return 当前日期时间
     */
    public static LocalDateTime nowDateTime() {
        return LocalDateTime.now();
    }

    /**
     * 获取当前时间戳（毫秒）
     *
     * @return 当前时间戳
     */
    public static long currentTimeMillis() {
        return System.currentTimeMillis();
    }

    /**
     * 获取当前时间戳（秒）
     *
     * @return 当前时间戳
     */
    public static long currentTimeSeconds() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 日期转字符串
     *
     * @param date 日期
     * @param formatter 格式化器
     * @return 格式化后的字符串
     */
    public static String format(LocalDate date, DateTimeFormatter formatter) {
        return date != null ? date.format(formatter) : null;
    }

    /**
     * 时间转字符串
     *
     * @param time 时间
     * @param formatter 格式化器
     * @return 格式化后的字符串
     */
    public static String format(LocalTime time, DateTimeFormatter formatter) {
        return time != null ? time.format(formatter) : null;
    }

    /**
     * 日期时间转字符串
     *
     * @param dateTime 日期时间
     * @param formatter 格式化器
     * @return 格式化后的字符串
     */
    public static String format(LocalDateTime dateTime, DateTimeFormatter formatter) {
        return dateTime != null ? dateTime.format(formatter) : null;
    }

    /**
     * 字符串转日期
     *
     * @param dateStr 日期字符串
     * @param formatter 格式化器
     * @return 日期
     */
    public static LocalDate parseDate(String dateStr, DateTimeFormatter formatter) {
        return StringUtils.isBlank(dateStr) ? null : LocalDate.parse(dateStr, formatter);
    }

    /**
     * 字符串转时间
     *
     * @param timeStr 时间字符串
     * @param formatter 格式化器
     * @return 时间
     */
    public static LocalTime parseTime(String timeStr, DateTimeFormatter formatter) {
        return StringUtils.isBlank(timeStr) ? null : LocalTime.parse(timeStr, formatter);
    }

    /**
     * 字符串转日期时间
     *
     * @param dateTimeStr 日期时间字符串
     * @param formatter 格式化器
     * @return 日期时间
     */
    public static LocalDateTime parseDateTime(String dateTimeStr, DateTimeFormatter formatter) {
        return StringUtils.isBlank(dateTimeStr) ? null : LocalDateTime.parse(dateTimeStr, formatter);
    }

    /**
     * Date转LocalDateTime
     *
     * @param date Date对象
     * @return LocalDateTime对象
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return date != null ? date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() : null;
    }

    /**
     * LocalDateTime转Date
     *
     * @param dateTime LocalDateTime对象
     * @return Date对象
     */
    public static Date toDate(LocalDateTime dateTime) {
        return dateTime != null ? Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()) : null;
    }

    /**
     * 获取指定日期的开始时间
     *
     * @param date 日期
     * @return 开始时间
     */
    public static LocalDateTime startOfDay(LocalDate date) {
        return date != null ? date.atStartOfDay() : null;
    }

    /**
     * 获取指定日期的结束时间
     *
     * @param date 日期
     * @return 结束时间
     */
    public static LocalDateTime endOfDay(LocalDate date) {
        return date != null ? date.atTime(LocalTime.MAX) : null;
    }

    /**
     * 获取指定日期所在月份的开始时间
     *
     * @param date 日期
     * @return 开始时间
     */
    public static LocalDateTime startOfMonth(LocalDate date) {
        return date != null ? date.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay() : null;
    }

    /**
     * 获取指定日期所在月份的结束时间
     *
     * @param date 日期
     * @return 结束时间
     */
    public static LocalDateTime endOfMonth(LocalDate date) {
        return date != null ? date.with(TemporalAdjusters.lastDayOfMonth()).atTime(LocalTime.MAX) : null;
    }

    /**
     * 获取指定日期所在年份的开始时间
     *
     * @param date 日期
     * @return 开始时间
     */
    public static LocalDateTime startOfYear(LocalDate date) {
        return date != null ? date.with(TemporalAdjusters.firstDayOfYear()).atStartOfDay() : null;
    }

    /**
     * 获取指定日期所在年份的结束时间
     *
     * @param date 日期
     * @return 结束时间
     */
    public static LocalDateTime endOfYear(LocalDate date) {
        return date != null ? date.with(TemporalAdjusters.lastDayOfYear()).atTime(LocalTime.MAX) : null;
    }

    /**
     * 计算两个日期之间的天数
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 天数
     */
    public static long daysBetween(LocalDate startDate, LocalDate endDate) {
        return startDate != null && endDate != null ? ChronoUnit.DAYS.between(startDate, endDate) : 0;
    }

    /**
     * 计算两个日期时间之间的小时数
     *
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 小时数
     */
    public static long hoursBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        return startDateTime != null && endDateTime != null ? ChronoUnit.HOURS.between(startDateTime, endDateTime) : 0;
    }

    /**
     * 计算两个日期时间之间的分钟数
     *
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 分钟数
     */
    public static long minutesBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        return startDateTime != null && endDateTime != null ? ChronoUnit.MINUTES.between(startDateTime, endDateTime) : 0;
    }

    /**
     * 计算两个日期时间之间的秒数
     *
     * @param startDateTime 开始日期时间
     * @param endDateTime 结束日期时间
     * @return 秒数
     */
    public static long secondsBetween(LocalDateTime startDateTime, LocalDateTime endDateTime) {
        return startDateTime != null && endDateTime != null ? ChronoUnit.SECONDS.between(startDateTime, endDateTime) : 0;
    }

    /**
     * 日期加减天数
     *
     * @param date 日期
     * @param days 天数
     * @return 计算后的日期
     */
    public static LocalDate plusDays(LocalDate date, long days) {
        return date != null ? date.plusDays(days) : null;
    }

    /**
     * 日期时间加减小时数
     *
     * @param dateTime 日期时间
     * @param hours 小时数
     * @return 计算后的日期时间
     */
    public static LocalDateTime plusHours(LocalDateTime dateTime, long hours) {
        return dateTime != null ? dateTime.plusHours(hours) : null;
    }

    /**
     * 日期时间加减分钟数
     *
     * @param dateTime 日期时间
     * @param minutes 分钟数
     * @return 计算后的日期时间
     */
    public static LocalDateTime plusMinutes(LocalDateTime dateTime, long minutes) {
        return dateTime != null ? dateTime.plusMinutes(minutes) : null;
    }

    /**
     * 日期时间加减秒数
     *
     * @param dateTime 日期时间
     * @param seconds 秒数
     * @return 计算后的日期时间
     */
    public static LocalDateTime plusSeconds(LocalDateTime dateTime, long seconds) {
        return dateTime != null ? dateTime.plusSeconds(seconds) : null;
    }
}